<template>
	<div ref="container" class="preview-3d"></div>
</template>

<script>
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";

export default {
	props: {
		features: { type: Array, required: true },
		height: { type: Number, default: 8 },
	},
	data() {
		return {
			scene: null,
			camera: null,
			renderer: null,
			controls: null,
			rooms: [],
			roads: [],
			startPoint: null,
			endPoint: null,
		};
	},
	mounted() {
		this.init3D();
		this.createBuildings();
		this.animate();
		this.$refs.container.addEventListener("click", this.onMouseClick);
	},
	methods: {
		init3D() {
			this.scene = new THREE.Scene();
			this.scene.background = new THREE.Color(0xffffff);

			this.camera = new THREE.PerspectiveCamera(
				75,
				this.$refs.container.clientWidth /
					this.$refs.container.clientHeight,
				0.1,
				1000
			);
			this.camera.position.set(0, 100, 150);

			this.renderer = new THREE.WebGLRenderer({ antialias: true });
			this.renderer.setSize(
				this.$refs.container.clientWidth,
				this.$refs.container.clientHeight
			);
			this.$refs.container.appendChild(this.renderer.domElement);

			this.controls = new OrbitControls(
				this.camera,
				this.renderer.domElement
			);
			this.controls.mouseButtons = {
				LEFT: this.controls.mouseButtons.RIGHT,
				RIGHT: this.controls.mouseButtons.LEFT,
			};
			this.controls.screenSpacePanning = false;
			this.controls.enableDamping = true;
			this.controls.minPolarAngle = 0;
			this.controls.maxPolarAngle = Math.PI / 2;

			this.scene.add(new THREE.AmbientLight(0xffffff, 0.5));

			const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
			directionalLight.position.set(10, 10, 10);
			this.scene.add(directionalLight);
		},
		createBuildings() {
			// 收集所有坐标点用于计算中心点
			let allCoordinates = [];
			this.features.forEach((feature) => {
				if (
					feature.layerType !== "path" &&
					feature.coordinates &&
					feature.coordinates[0] &&
					Array.isArray(feature.coordinates[0])
				) {
					// 过滤无效坐标
					allCoordinates = allCoordinates.concat(
						this.filterValidCoordinates(feature.coordinates[0])
					);
				}
			});

			// 计算中心点坐标
			let centerX = 112.45,
				centerY = 37.75;
			if (allCoordinates.length > 0) {
				const xs = allCoordinates
					.map((coord) => coord[0])
					.filter((x) => !isNaN(x));
				const ys = allCoordinates
					.map((coord) => coord[1])
					.filter((y) => !isNaN(y));

				if (xs.length > 0 && ys.length > 0) {
					centerX = (Math.min(...xs) + Math.max(...xs)) / 2;
					centerY = (Math.min(...ys) + Math.max(...ys)) / 2;
				}
			}

			// 分别处理不同类型的特征
			this.features.forEach((feature) => {
				if (!feature.coordinates || !feature.coordinates[0]) {
					console.warn("特征缺少坐标数据:", feature);
					return;
				}

				if (feature.layerType === "floor") {
					this.createFloor(
						feature.coordinates[0],
						centerX,
						centerY,
						8
					);
				} else if (feature.layerType === "room") {
					this.createRoom(
						feature.coordinates[0],
						centerX,
						centerY,
						8
					);
				}
			});
		},
		createRoom(coordinates, centerX, centerY, height) {
			// 过滤无效坐标点
			coordinates = this.filterValidCoordinates(coordinates);
			if (coordinates.length < 3) {
				console.warn("房间坐标点不足，至少需要3个点:", coordinates);
				return;
			}

			// 创建点集合
			const points = coordinates.map((coord) => {
				return new THREE.Vector2(
					(coord[0] - centerX) * 1000,
					(coord[1] - centerY) * 1000
				);
			});

			// 验证并修复自相交的形状
			if (!this.isValidShape(points)) {
				console.warn("房间形状无效，尝试修复...");
				points = this.fixShape(points);

				if (points.length < 3) {
					console.error("无法修复房间形状，跳过创建");
					return;
				}
			}

			// 创建房间形状
			const shape = new THREE.Shape(points);
			const roomHeight = height;

			// 创建几何体
			const geometry = new THREE.ExtrudeGeometry(shape, {
				depth: roomHeight,
				bevelEnabled: true,
				curveSegments: 1,
				steps: 1,
			});

			// 验证几何体
			if (!this.validateGeometry(geometry)) {
				console.error("房间几何体无效，跳过创建");
				return;
			}

			// 创建材质和网格
			const material = new THREE.MeshLambertMaterial({
				color: 0x87ceeb,
				side: THREE.DoubleSide,
				transparent: false,
				opacity: 0.5,
			});

			const room = new THREE.Mesh(geometry, material);
			room.rotation.x = -Math.PI / 2;
			room.position.y = -height + 1;
			room.userData = {
				originalColor: 0x87ceeb,
				type: "room",
				center: this.getRoomCenter(room),
			};

			this.rooms.push(room);
			this.scene.add(room);

			// 添加顶面边缘蓝色周长线
			const linePoints = points.map(
				(p) => new THREE.Vector3(p.x, p.y, roomHeight)
			);
			if (
				points.length > 0 &&
				!points[0].equals(points[points.length - 1])
			) {
				linePoints.push(
					new THREE.Vector3(points[0].x, points[0].y, roomHeight)
				);
			}

			if (linePoints.length >= 2) {
				const lineGeometry = new THREE.BufferGeometry().setFromPoints(
					linePoints
				);
				const lineMaterial = new THREE.LineBasicMaterial({
					color: 0x0000ff,
					linewidth: 5,
					transparent: false,
					depthTest: true,
					depthWrite: true,
				});

				const perimeterLine = new THREE.Line(
					lineGeometry,
					lineMaterial
				);
				perimeterLine.rotation.x = -Math.PI / 2;
				perimeterLine.position.y = -height + 1.2;
				perimeterLine.updateMatrix();
				this.scene.add(perimeterLine);
			} else {
				console.warn(
					"无法创建房间周长线，点数量不足:",
					linePoints.length
				);
			}
		},
		createRoad(coordinates, centerX, centerY, height) {
			// 过滤无效坐标点
			coordinates = this.filterValidCoordinates(coordinates);
			if (coordinates.length < 3) {
				console.warn("道路坐标点不足，至少需要3个点:", coordinates);
				return;
			}

			// 创建点集合
			const points = coordinates.map((coord) => {
				return new THREE.Vector2(
					(coord[0] - centerX) * 1000,
					(coord[1] - centerY) * 1000
				);
			});

			// 验证并修复自相交的形状
			if (!this.isValidShape(points)) {
				console.warn("道路形状无效，尝试修复...");
				points = this.fixShape(points);

				if (points.length < 3) {
					console.error("无法修复道路形状，跳过创建");
					return;
				}
			}

			// 创建道路形状
			const shape = new THREE.Shape(points);
			const geometry = new THREE.ShapeGeometry(shape);

			// 验证几何体
			if (!this.validateGeometry(geometry)) {
				console.error("道路几何体无效，跳过创建");
				return;
			}

			// 创建材质和网格
			const material = new THREE.MeshBasicMaterial({
				color: 0x999999,
				transparent: true,
				opacity: 0.8,
			});

			const road = new THREE.Mesh(geometry, material);
			road.rotation.x = -Math.PI / 2;
			road.position.y = 0.1;
			road.userData = {
				type: "road",
				shape: shape,
				points: points,
			};

			this.roads.push(road);
			this.scene.add(road);
		},
		createFloor(coordinates, centerX, centerY, height) {
			// 过滤无效坐标点
			coordinates = this.filterValidCoordinates(coordinates);
			if (coordinates.length < 3) {
				console.warn("楼板坐标点不足，至少需要3个点:", coordinates);
				return;
			}

			// 创建点集合
			const points = coordinates.map((coord) => {
				return new THREE.Vector2(
					(coord[0] - centerX) * 1000,
					(coord[1] - centerY) * 1000
				);
			});

			// 验证并修复自相交的形状
			if (!this.isValidShape(points)) {
				console.warn("楼板形状无效，尝试修复...");
				points = this.fixShape(points);

				if (points.length < 3) {
					console.error("无法修复楼板形状，跳过创建");
					return;
				}
			}

			// 创建楼板形状
			const shape = new THREE.Shape(points);
			const slabThickness = 1;

			// 创建几何体
			const geometry = new THREE.ExtrudeGeometry(shape, {
				depth: slabThickness,
				bevelEnabled: true,
				curveSegments: 1,
				steps: 1,
			});

			// 验证几何体
			if (!this.validateGeometry(geometry)) {
				console.error("楼板几何体无效，跳过创建");
				return;
			}

			// 创建材质和网格
			const material = new THREE.MeshLambertMaterial({
				color: 0xf5f5f5,
				side: THREE.DoubleSide,
				transparent: false,
				opacity: 1.0,
			});

			const floorSlab = new THREE.Mesh(geometry, material);
			floorSlab.rotation.x = -Math.PI / 2;
			floorSlab.position.y = -height + slabThickness / 2;
			this.scene.add(floorSlab);
		},
		getRoomCenter(room) {
			if (!room) return new THREE.Vector3();

			const box = new THREE.Box3().setFromObject(room);
			const center = new THREE.Vector3();
			box.getCenter(center);
			return center;
		},

		// 过滤无效坐标点
		filterValidCoordinates(coordinates) {
			if (!Array.isArray(coordinates)) {
				console.warn("坐标数据不是数组:", coordinates);
				return [];
			}

			return coordinates.filter((coord) => {
				if (!Array.isArray(coord) || coord.length < 2) {
					console.warn("无效坐标点:", coord);
					return false;
				}

				// 检查坐标是否为有效数字
				if (isNaN(coord[0]) || isNaN(coord[1])) {
					console.warn("坐标包含NaN值:", coord);
					return false;
				}

				// 检查坐标是否为无穷大
				if (!isFinite(coord[0]) || !isFinite(coord[1])) {
					console.warn("坐标包含无穷大值:", coord);
					return false;
				}

				return true;
			});
		},
		// 验证形状有效性
		isValidShape(points) {
			return true;
			if (!Array.isArray(points) || points.length < 3) {
				return false;
			}

			// 检查是否有重复点
			for (let i = 0; i < points.length; i++) {
				for (let j = i + 1; j < points.length; j++) {
					if (points[i].equals(points[j])) {
						return false;
					}
				}
			}

			return true;
		},
		// 修复无效形状
		fixShape(points) {
			if (!Array.isArray(points)) return [];

			// 移除重复点
			const uniquePoints = [];
			points.forEach((point) => {
				if (!uniquePoints.some((p) => p.equals(point))) {
					uniquePoints.push(point);
				}
			});

			return uniquePoints;
		},
		// 验证几何体有效性
		validateGeometry(geometry) {
			if (
				!geometry ||
				!geometry.attributes ||
				!geometry.attributes.position
			) {
				return false;
			}

			const position = geometry.attributes.position;

			// 检查顶点数量
			if (position.count < 3) {
				console.warn("几何体顶点数量不足:", position.count);
				return false;
			}

			// 检查是否有NaN或无穷大值
			for (let i = 0; i < position.count; i++) {
				if (
					isNaN(position.getX(i)) ||
					isNaN(position.getY(i)) ||
					isNaN(position.getZ(i)) ||
					!isFinite(position.getX(i)) ||
					!isFinite(position.getY(i)) ||
					!isFinite(position.getZ(i))
				) {
					console.warn("几何体包含无效顶点数据，索引:", i);
					return false;
				}
			}

			return true;
		},

		onMouseClick(event) {
			if (!this.$refs.container) return;

			// 计算鼠标在标准化设备坐标中的位置 (-1 到 1)
			const rect = this.$refs.container.getBoundingClientRect();
			const mouse = new THREE.Vector2();
			mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
			mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

			// 创建射线投射器
			if (!this.camera) return;

			const raycaster = new THREE.Raycaster();
			raycaster.setFromCamera(mouse, this.camera);

			// 检测与房间对象的交集
			if (!this.rooms || this.rooms.length === 0) return;

			const intersects = raycaster.intersectObjects(this.rooms);

			if (intersects.length > 0 && intersects[0].object) {
				const clickedRoom = intersects[0].object;

				// 重置所有房间颜色
				this.rooms.forEach((room) => {
					if (room && room.material && room.userData) {
						room.material.color.set(room.userData.originalColor);
					}
				});

				// 点击逻辑：如果没有起点，设置为起点；如果已有起点但没有终点，设置为终点；如果都有，重置并设置新起点
				if (!this.startPoint) {
					// 设置起点
					this.startPoint = clickedRoom;
					if (this.startPoint && this.startPoint.material) {
						this.startPoint.material.color.set(0x00ff00);
					}
					this.endPoint = null; // 重置终点
				} else if (!this.endPoint && clickedRoom !== this.startPoint) {
					// 设置终点（不能与起点相同）
					this.endPoint = clickedRoom;
					if (this.endPoint && this.endPoint.material) {
						this.endPoint.material.color.set(0xff0000);
					}

					// 当起点和终点都存在时绘制路径
					if (this.startPoint && this.endPoint) {
						// 获取两个房间的中心点
						const startCenter = this.getRoomCenter(this.startPoint);
						const endCenter = this.getRoomCenter(this.endPoint);
					}
				} else {
					// 重置并设置新起点
					this.startPoint = clickedRoom;
					if (this.startPoint && this.startPoint.material) {
						this.startPoint.material.color.set(0x00ff00);
					}
					this.endPoint = null; // 重置终点
				}
			}
		},
		animate() {
			requestAnimationFrame(this.animate.bind(this));
			if (this.controls) this.controls.update();
			if (this.renderer && this.scene && this.camera) {
				this.renderer.render(this.scene, this.camera);
			}
		},
	},
	beforeUnmount() {
		// 清理资源
		if (this.$refs.container) {
			this.$refs.container.removeEventListener(
				"click",
				this.onMouseClick
			);
		}

		if (this.renderer) {
			this.renderer.dispose();
			if (this.$refs.container) {
				this.$refs.container.removeChild(this.renderer.domElement);
			}
		}

		if (this.controls) this.controls.dispose();
	},
	watch: {
		features: {
			deep: true,
			handler() {
				// 特征变化时重新渲染
				if (!this.scene) return;

				this.scene.traverse((child) => {
					if (
						child instanceof THREE.Mesh &&
						child !== this.controls?.object &&
						!child.isCube
					) {
						this.scene.remove(child);
					}
				});

				this.rooms = [];
				this.roads = [];

				this.createBuildings();
			},
		},
	},
};
</script>

<style scoped>
.preview-3d {
	width: 100%;
	height: 100%;
}
</style>
